home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************/
- /* Copyright(c) 1987, 1992 by BBN Systems and Technologies, */
- /* A Division of Bolt Beranek and Newman Inc. */
- /* */
- /* RDP implementation for 4.2/4.3bsd by Craig Partridge */
- /* */
- /* Permission to use, copy, modify, distribute, and sell this software */
- /* and its documentation for any purpose is hereby granted without fee, */
- /* provided that the above copyright notice and this permission appear */
- /* in all copies and in supporting documentation, and that the name of */
- /* Bolt Beranek and Newman Inc. not be used in advertising or */
- /* publicity pertaining to distribution of the software without */
- /* specific, written prior permission. BBN makes no representations */
- /* about the suitability of this software for any purposes. It is */
- /* provided "AS IS" without express or implied warranties. */
- /**************************************************************************/
-
- #include "../h/param.h"
- #include "../h/dir.h"
- #include "../h/user.h"
- #include "../h/mbuf.h"
- #include "../h/protosw.h"
- #include "../h/socket.h"
- #include "../h/socketvar.h"
- #include "../h/errno.h"
-
- #include "../net/if.h"
- #include "../net/route.h"
-
- #include "../netinet/in.h"
- #include "../netinet/in_pcb.h"
- #include "../netinet/in_systm.h"
- #include "../netinet/ip.h"
- #include "../netinet/ip_var.h"
- #include "../netinet/ip_icmp.h"
-
- #include "../netinet/rdp.h"
- #include "../netinet/rdp_var.h"
- #include "../netinet/rdp_ip.h"
- #include "../netinet/rdp_conf.h"
-
-
- extern u_long rdpserial;
- extern u_short rdp_mtu;
- extern short rdp_start[];
- extern struct inpcb rdb;
-
- struct mbuf rdp_mark; /* a fake mbuf to mark packets rcvd */
-
- /**************************************************************************/
- /* INPUT routine */
- /**************************************************************************/
-
- #ifndef BSD4_3
- rdp_input(m0)
- #else
- rdp_input(m0, ifp)
- struct ifnet *ifp;
- #endif
- struct mbuf *m0;
- {
- register struct rdpcb *rp;
- register struct rdpip *ri;
- register struct rdpque *rq;
- register int i, j;
- struct mbuf *m;
- struct inpcb *inp;
- struct socket *so;
- u_long savsum, seq;
- int hlen;
- u_short dlen;
-
- rdp_info.rst_ipackets++;
-
- /* get everything up front */
- m = m0;
- if ((m->m_len < RI_SIZE) && ((m = m_pullup(m,RI_SIZE))==0))
- {
- rdp_info.rst_len++;
- #ifdef DEBUG
- printf("rdp_input: m_pullup 1\n");
- #endif
- goto release;
- }
-
- ri = mtod(m, struct rdpip *);
-
- /* check version */
- if ((ri->ri_flags & RH_VERBITS) != R_VERSION)
- {
- #ifdef DEBUG
- printf("rdp_input: version mismatch\n");
- #endif
- goto release;
- }
-
- /* strip ip options */
- if (ri->ri_hl > (sizeof(struct ip) >> 2))
- ip_stripoptions((struct ip *)ri,(struct mbuf *)0);
-
- /* now pull all the header stuff */
- hlen = (ri->ri_hlen << 1) + sizeof(struct ip);
- if (hlen > MLEN)
- {
- /* ought to strip excess EACKs? -- or otherwise fiddle? */
- /* this is just because I haven't thought this out */
- panic("rdp_input: hlen");
- }
-
- if ((hlen > m->m_len) && ((m = m_pullup(m,hlen))==0))
- {
- #ifdef DEBUG
- printf("rdp_input: m_pullup 2\n");
- #endif
- rdp_info.rst_len++;
- goto release;
- }
-
- /* now get total packet len and adjust hlen to just rdp hdr */
- dlen = ntohs(ri->ri_dlen);
- hlen -= sizeof(struct ip);
-
- #ifdef DEBUG
- /* rdp_pktprt(ri); */
- #endif
-
- /* note that IP subtracted IP header len from ri_len */
- if (ri->ri_len < (hlen+dlen))
- {
- #ifdef DEBUG
- printf("rdp_input: rdp length\n");
- #endif
- rdp_info.rst_len++;
- goto release;
- }
-
- /* now checksum time */
- savsum = ri->ri_sum;
- ri->ri_sum = 0;
-
- /* adjust mbuf to lose ip header */
- m->m_len -= sizeof(struct ip);
- m->m_off += sizeof(struct ip);
-
- if (savsum != in_cksum(m,(int)dlen + hlen))
- {
- #ifdef DEBUG
- printf("rdp_input: bad cksum, 0x%x\n",savsum);
- #endif
- rdp_info.rst_cksum++;
- goto release;
- }
-
- /* get rid of rdp header in mbuf but note ri still valid */
- m->m_len -= hlen;
- m->m_off += hlen;
-
- /* find rdpcb */
- inp = in_pcblookup(&rdb,ri->ri_src,ri->ri_sport,ri->ri_dst,ri->ri_dport,INPLOOKUP_WILDCARD);
- if (inp == 0)
- {
- #ifdef DEBUG
- printf("rdp_input: no destination for packet\n");
- #endif
- /* act closed here ... */
- (void) rdp_iclosed((struct inpcb *)0,(struct rdpcb *)0,ri);
- goto release;
- }
-
- rp = (struct rdpcb *)inp->inp_ppcb;
-
- /* now figure out what to do */
- switch(rp->rp_state)
- {
- case R_OPEN:
- if (rdp_iopen(inp,rp,ri)==0)
- goto release;
- break;
-
- case R_SYN_RCVD:
- if (rdp_ircvdsyn(inp,rp,ri)==0)
- goto release;
- break;
-
- case R_LISTEN:
- (void) rdp_ilisten(inp,rp,ri);
- goto release;
-
- case R_CLOSED:
- (void) rdp_iclosed(inp,rp,ri);
- goto release;
-
- case R_SYN_SENT:
- (void) rdp_isynsent(inp,rp,ri);
- goto release;
-
- case R_CLOSE_WAIT:
- (void) rdp_iclowait(inp,rp,ri);
- goto release;
-
- case R_DRAIN:
- (void)rdp_idrain(inp,rp,ri);
- goto release;
- }
-
- /* now, we are only here if packet should go in our data queues */
-
- /* reset activity timer */
- rp->rp_timer = RT_NULLTIME;
-
- seq = ntohl(ri->ri_sn);
- rq = rp->rp_rq;
-
- i = (seq - rp->rp_rcvcur - 1 + rq->rq_rcvbase) % R_RCVWIN;
-
- /* do we already have it? */
- if (rq->rq_rcvq[i] != 0)
- {
- /* we could send EACK, but that is probably excessive */
- rdp_info.rst_dup++;
- goto release;
- }
-
- /* new hi? */
- if (seq_gt(seq,rp->rp_rcvhi))
- rp->rp_rcvhi = seq;
-
- so = inp->inp_socket;
-
- #ifndef BSD4_3
- /* mark the end of the packet -- sbappend should do this but doesn't */
- for(m0=m; m->m_next != 0; m = m->m_next);
-
- m->m_act = (struct mbuf *)1;
- m = m0;
- #endif /* not 4.3 */
-
-
- if ((so->so_type == SOCK_RDM) && (ri->ri_flags & RH_NULL)==0)
- {
- /* give it to the user */
- if (sbspace(&(so->so_rcv)) <= 0)
- {
- so->so_error = ENOBUFS;
- rdp_fatal(inp);
- goto release;
- }
- #ifdef BSD4_3
- sbappendrecord(&(so->so_rcv),m);
- #else
- sbappend(&(so->so_rcv),m);
- #endif
- sorwakeup(so);
-
- /* and mark that we took it */
- rq->rq_rcvq[i] = &rdp_mark;
- }
- else
- {
- /* just queue it */
- if (ri->ri_flags & RH_NULL)
- {
- rq->rq_rcvq[i] = &rdp_mark;
- /* and get rid of m */
- (void) m_freem(m);
- }
- else
- rq->rq_rcvq[i] = m;
- }
-
- /* now, was the packet on the left edge? */
- if (seq == (rp->rp_rcvcur+1))
- {
- /* find next unacked packet */
- i = rp->rp_rcvhi - rp->rp_rcvcur;
-
- j = rq->rq_rcvbase;
-
- for(; i > 0; i--)
- {
- if ((m = rq->rq_rcvq[j]) == 0)
- break;
-
- /* mark that packet is spent */
- rq->rq_rcvq[j] = 0;
- rp->rp_rcvcur++;
- rp->rp_rcvuer++;
-
- if (m != &rdp_mark)
- {
- /* pass stuff up... */
- if (sbspace(&(so->so_rcv)) <= 0)
- {
- so->so_error = ENOBUFS;
- rdp_fatal(inp);
- /* release m which we just dequeued */
- goto release;
- }
- #ifdef BSD4_3
- sbappendrecord(&(so->so_rcv),m);
- #else
- sbappend(&(so->so_rcv),m);
- #endif /* 4.3 */
- sorwakeup(so);
- }
-
- if (++j == R_RCVWIN)
- j = 0;
- }
-
- rq->rq_rcvbase = j;
- }
-
- /*
- * send ack for left window. RFC says just send ACK if packet
- * is in sequence and EACK if out of sequence. That seems
- * a bit odd. Just because a packet is on the left edge
- * doesn't mean we don't have other gaps.
- */
-
- (void)rdp_ack(inp,rp->rp_sndnxt,rp->rp_rcvcur);
- return;
-
- release:
- /* note that most things here are small segments */
- if (m != 0)
- {
- MFREE(m,m0);
- if (m0 != 0)
- (void) m_freem(m0);
- }
- }
-
- /**************************************************************************/
- /* LISTEN */
- /**************************************************************************/
-
- rdp_ilisten(inp,rp,ri)
- struct inpcb *inp;
- struct rdpcb *rp;
- struct rdpip *ri;
- {
- struct inpcb tmpinp;
- struct rdpsyn *rs;
- register struct inpcb *inp2;
- register struct rdpcb *rp2;
- struct rdpque *rq2;
- register struct socket *sonew;
-
- #ifdef lint
- rp = rp;
- #endif
-
- if (ri->ri_flags & RH_RST)
- goto done;
-
- /* a data packet? */
- if ((ri->ri_flags & RH_ACK) || (ri->ri_flags & RH_NULL))
- {
- /* got to build fake inp to reply here */
- bcopy((caddr_t)inp,(caddr_t)&tmpinp,sizeof(tmpinp));
- tmpinp.inp_faddr = ri->ri_src;
- tmpinp.inp_fport = ri->ri_sport;
-
- (void) rdp_rst(&tmpinp,0,(u_long)(ntohl(ri->ri_an)+1),(u_long)0,0);
- goto done;
- }
-
- /*
- * RFC doesn't anticipate situation in which we run out of resources
- * on the SYN. We act as if we had crashed, and are closed.
- */
-
- if (ri->ri_flags & RH_SYN)
- {
- if ((sonew = sonewconn(inp->inp_socket))==0)
- {
- /* got to build fake inp to reply here */
- bcopy((caddr_t)inp,(caddr_t)&tmpinp,sizeof(tmpinp));
- tmpinp.inp_faddr = ri->ri_src;
- tmpinp.inp_fport = ri->ri_sport;
-
- (void) rdp_rst(&tmpinp,1,(u_long)0,(u_long)ntohl(ri->ri_sn),0);
- goto done;
- }
-
- /* set up new socket */
- inp2 = sotoinpcb(sonew);
- inp2->inp_laddr = inp->inp_laddr;
- inp2->inp_faddr = ri->ri_src;
- inp2->inp_lport = inp->inp_lport;
- inp2->inp_fport = ri->ri_sport;
-
- rp2 = (struct rdpcb *)inp2->inp_ppcb;
- rq2 = rp2->rp_rq;
-
- rp2->rp_rcvhi = rp2->rp_rcvcur = ntohl(ri->ri_sn);
- rp2->rp_rcvuer = rp2->rp_rcvcur + 1 + R_RCVWIN;
- rp2->rp_sndhsa = rp2->rp_sndnxt = rdpserial++;
- rp2->rp_snduna = rp2->rp_sndnxt;
- rp2->rp_state = R_SYN_RCVD;
-
- /* get the syn variables -- flags aren't interesting */
-
- rs = (struct rdpsyn *)(((caddr_t)ri) + RI_SIZE);
- rp2->rp_sndmax = ntohs(rs->rs_mos);
- if (rp2->rp_sndmax > R_MAXSND)
- rp2->rp_sndmax = R_MAXSND;
- rp2->rp_maxinflt = rp2->rp_sndmax;
-
- rp2->rp_sndbuf = ntohs(rs->rs_mss);
- if (rp2->rp_sndbuf > rdp_mtu)
- rp2->rp_sndbuf = rdp_mtu;
-
- /* steal first timer to retransmit syns */
- rq2->rq_retries[0] = 0;
- rq2->rq_sndtimer[0] = 0;
-
- /* sndnxt == sndiss */
- (void) rdp_syn(inp2,1,rp2->rp_sndnxt,rp2->rp_rcvcur);
- }
-
- done:
- return(0);
- }
-
- /**************************************************************************/
- /* CLOSED */
- /**************************************************************************/
-
- rdp_iclosed(inp,rp,ri)
- struct inpcb *inp;
- struct rdpcb *rp;
- struct rdpip *ri;
- {
- struct inpcb tmpinp;
-
- #ifdef lint
- rp = rp;
- #endif
-
-
- if (ri->ri_flags & RH_RST)
- goto done;
-
- /* we have to reply... */
- if (inp == 0)
- {
- tmpinp.inp_laddr = ri->ri_dst;
- tmpinp.inp_lport = ri->ri_dport;
- }
- else
- bcopy((caddr_t)inp,(caddr_t)&tmpinp,sizeof(tmpinp));
-
- tmpinp.inp_faddr = ri->ri_src;
- tmpinp.inp_fport = ri->ri_sport;
-
-
- /* a data segment?? */
- if ((ri->ri_flags & RH_ACK) || (ri->ri_flags & RH_NULL))
- {
- (void) rdp_rst(&tmpinp,0,(u_long)(ntohl(ri->ri_an)+1),(u_long)0,0);
- }
- else
- {
- /*
- * RFC PROBLEM: page 24 says use rcv.cur, but we aren't open
- * so rcv.cur is meaningless.
- */
- (void) rdp_rst(&tmpinp,1,(u_long)0,(u_long)ntohl(ri->ri_sn),0);
- }
-
- done:
- return(0);
- }
-
- /**************************************************************************/
- /* CLOSE WAIT */
- /**************************************************************************/
-
- /*ARGSUSED*/
-
- rdp_iclowait(inp,rp,ri)
- struct inpcb *inp;
- struct rdpcb *rp;
- struct rdpip *ri;
- {
-
- /*
- * RFC PROBLEM: page 13 and figure 3 on page 10 suggest we stay in
- * this state and drop all segments. Page 24 says we go to CLOSED
- * on RST. The first two outvote the third (and seem to make more sense).
- */
-
- #ifdef notdef
- if (ri->ri_flags & RH_RST)
- {
- rp->rp_state = R_CLOSED;
- rp->rp_timer = 0;
- (void) rdp_detach(inp->inp_socket,inp);
- }
- #endif
-
- return(0);
- }
-
- /**************************************************************************/
- /* SYN SENT */
- /**************************************************************************/
-
- rdp_isynsent(inp,rp,ri)
- struct inpcb *inp;
- register struct rdpcb *rp;
- struct rdpip *ri;
- {
- struct rdpsyn *rs;
- register struct rdpque *rq = rp->rp_rq;
-
- /*
- * RFC has all these tests out of order on pages 25-26
- * got to test RST and SYN before ACK!
- */
-
- if (ri->ri_flags & RH_RST)
- {
- /* RST -- may have to close */
-
- if (ri->ri_flags & RH_ACK)
- {
- inp->inp_socket->so_error = ECONNREFUSED;
- (void) rdp_fatal(inp);
- }
- }
- else if (ri->ri_flags & RH_SYN)
- {
- /* SYN -- try to finish up the open */
-
- rp->rp_rcvhi = rp->rp_rcvcur = ntohl(ri->ri_sn);
- rp->rp_rcvuer = rp->rp_rcvcur + 1 + R_RCVWIN;
-
- /* grab the syn variables -- ignore the flags */
-
- rs = (struct rdpsyn *)((caddr_t)ri + RI_SIZE);
- rp->rp_sndmax = ntohs(rs->rs_mos);
- if (rp->rp_sndmax > R_MAXSND)
- rp->rp_sndmax = R_MAXSND;
- rp->rp_maxinflt = rp->rp_sndmax;
-
- rp->rp_sndbuf = ntohs(rs->rs_mss);
- if (rp->rp_sndbuf > rdp_mtu)
- rp->rp_sndbuf = rdp_mtu;
-
- if (ri->ri_flags & RH_ACK)
- {
- /* turn off the timer */
- rp->rp_state = R_OPEN;
- rp->rp_timer = RT_NULLTIME;
-
- rp->rp_sndnxt++;
- rp->rp_snduna++;
- rp->rp_estrtt = rq->rq_sndtimer[0] * RT_G;
- if (rp->rp_estrtt < (RT_G * RT_RTMIN))
- rp->rp_estrtt = RT_G * RT_RTMIN;
-
- soisconnected(inp->inp_socket);
- /* rcvcur == rcvirs */
- (void) rdp_ack(inp,rp->rp_sndnxt,rp->rp_rcvcur);
- }
- else
- {
- rp->rp_state = R_SYN_RCVD;
- rq->rq_retries[0] = 0;
- rq->rq_sndtimer[0] = 0;
- /* rcvcur == rcvirs, sndnxt == sndiss */
- (void) rdp_syn(inp,1,rp->rp_sndnxt,rp->rp_rcvcur);
- }
- }
- else if (ri->ri_flags & RH_ACK)
- {
- /* ACK */
-
- /* sndnxt == sndiss */
- if (ntohl(ri->ri_an) != rp->rp_sndnxt)
- {
- /* they don't like us and we don't like them */
- (void) rdp_rst(inp,1,(u_long)0,(u_long)(ntohl(ri->ri_an)+1),1);
- inp->inp_socket->so_error = ECONNABORTED;
- (void) rdp_fatal(inp);
- }
- }
-
- return(0);
- }
-
- /**************************************************************************/
- /* SYN RCVD */
- /**************************************************************************/
-
- rdp_ircvdsyn(inp,rp,ri)
- struct inpcb *inp;
- struct rdpcb *rp;
- struct rdpip *ri;
- {
- struct socket *so = inp->inp_socket;
- struct rdpque *rq = rp->rp_rq;
- u_long seq = ntohl(ri->ri_sn);
-
- /* packet has to be in sequence -- note that (rcvcur == rcvirs) */
- if (seq_ge(rp->rp_rcvcur,seq) || seq_ge(seq,rp->rp_rcvuer))
- {
- /* packet not in sequence */
- (void) rdp_ack(inp,rp->rp_sndnxt,rp->rp_rcvcur);
- rdp_info.rst_range++;
- goto done;
- }
-
- if (ri->ri_flags & RH_RST)
- {
- /* active open then return error to user */
- inp->inp_socket->so_error = ECONNREFUSED;
- (void) rdp_fatal(inp);
- goto done;
- }
-
- if (ri->ri_flags & RH_SYN)
- {
- (void) rdp_rst(inp,0,(u_long)(ntohl(ri->ri_an)+1),(u_long)0,1);
- inp->inp_socket->so_error = ECONNRESET;
- (void) rdp_fatal(inp);
- goto done;
- }
-
-
- /*
- * ack and eack tests folded together in next few lines
- */
-
- /* sndnxt == sndiss */
- if ((ri->ri_flags & RH_ACK) && (ntohl(ri->ri_an) == rp->rp_sndnxt))
- goto open;
-
- if ((ri->ri_flags & RH_ACK) || (ri->ri_flags & RH_EACK))
- {
- /*
- * RFC PROBLEM: doesn't say to close but we are forcing
- * other end to close, so we should.
- */
-
- (void) rdp_rst(inp,0,(u_long)(ntohl(ri->ri_an)+1),(u_long)0,1);
- inp->inp_socket->so_error = ECONNABORTED;
- (void) rdp_fatal(inp);
- goto done;
- }
-
- open:
- rp->rp_state = R_OPEN;
- rp->rp_timer = RT_NULLTIME;
-
- rp->rp_estrtt = rq->rq_sndtimer[0] * RT_G;
- if (rp->rp_estrtt < (RT_G * RT_RTMIN))
- rp->rp_estrtt = RT_G * RT_RTMIN;
- rp->rp_sndnxt++;
- rp->rp_snduna++;
- soisconnected(so);
-
- /* do we have any data? */
- if ((ntohs(ri->ri_dlen) != 0) || (ri->ri_flags & RH_NULL))
- return(1);
-
- done:
- return(0);
- }
-
- /**************************************************************************/
- /* OPEN */
- /**************************************************************************/
-
- rdp_iopen(inp,rp,ri)
- struct inpcb *inp;
- register struct rdpcb *rp;
- register struct rdpip *ri;
- {
- register short i, j;
- register struct rdpque *rq = rp->rp_rq;
- register int numacks=0;
- struct socket *so = inp->inp_socket;
- struct mbuf *m;
- u_long seq = ntohl(ri->ri_sn);
- u_long ack;
- u_long *ea;
-
- /* packet in sequence? */
- if (seq_le(seq,rp->rp_rcvcur) || seq_le(rp->rp_rcvuer,seq))
- {
- /* no ... */
- (void) rdp_ack(inp,rp->rp_sndnxt,rp->rp_rcvcur);
- rdp_info.rst_range++;
- goto discard;
- }
-
- /*
- * RFC PROBLEM: RFC only treats the case in which this is an
- * error - but if no data outstanding, it is a real close.
- */
- if (ri->ri_flags & RH_RST)
- {
- soisdisconnected(so);
- rp->rp_state = R_CLOSE_WAIT;
- rp->rp_timer = RT_CLOTIME + (R_MAXTRIES * rp->rp_estrtt);
-
- /* a bad close?? */
- if (rdp_clrq(rp) || (ntohl(ri->ri_sn) != rp->rp_rcvcur+1))
- so->so_error = ECONNRESET;
-
- /* don't bother to send RST back */
- rq->rq_retries[0] = R_MAXTRIES;
-
- goto discard;
- }
-
- if (ri->ri_flags & RH_SYN)
- {
- (void) rdp_rst(inp,0,(u_long)(ntohl(ri->ri_an)+1),(u_long)0,1);
-
- /* now close down */
- inp->inp_socket->so_error = ECONNRESET;
- (void) rdp_fatal(inp);
- goto discard;
- }
-
- if (ri->ri_flags & RH_ACK)
- {
- ack = ntohl(ri->ri_an);
-
- if (seq_le(rp->rp_snduna,ack) && seq_lt(ack,rp->rp_sndnxt))
- {
-
- /* new rtt */
- #ifdef ALTRTT
- i = ( ack - rp->rp_snduna + rq->rq_sndbase ) % R_MAXSND;
- if (seq_gt(ack,rp->rp_sndhsa) || (rq->rq_retries[i]==0))
- {
- rp->rp_sndhsa = ack;
- rdp_newrtt(&(rp->rp_srtt),rq->rq_sndtimer[i]);
- rp->rp_lastrtt = rq->rq_sndtimer[i];
- }
- #endif
-
- /* compute number of packets acked */
- i = (ack - rp->rp_snduna)+1;
- j = rq->rq_sndbase;
-
- for(; i>0; i--)
- {
- if ((m = rq->rq_sndq[j]) != 0)
- {
- numacks++;
- #ifdef OLDRTT
- rdp_newrtt(&(rp->rp_srtt),rq->rq_sndtimer[j]);
- rp->rp_lastrtt = rq->rq_sndtimer[j];
- #endif
- (void) m_freem(m);
- }
-
- /* increment pointer */
- if (++j == R_MAXSND)
- j = 0;
- }
-
- rq->rq_sndbase = j;
- rp->rp_snduna = ack + 1;
- }
- }
-
- /* keep going... */
-
- if (ri->ri_flags & RH_EACK)
- {
- ea = (u_long *)(((caddr_t)ri)+RI_SIZE);
-
- i = (ri->ri_hlen - (R_HDRSIZE >> 1)) >> 1;
-
- for(; i > 0; i--, ea++)
- {
- *ea = ntohl(*ea);
-
- /*
- * use una+1 to keep from having to worry about left
- * edge shifts, which *should* never happen anyway.
- */
-
- if (seq_le(rp->rp_snduna+1,*ea) && seq_lt(*ea,rp->rp_sndnxt))
- {
-
- j = (*ea - rp->rp_snduna + rq->rq_sndbase) % R_MAXSND;
-
- if (rq->rq_sndq[j] != 0)
- {
- numacks++;
- #ifdef OLDRTT
- rdp_newrtt(&(rp->rp_srtt),rq->rq_sndtimer[j]);
- rp->rp_lastrtt = rq->rq_sndtimer[j];
- #else /* ALTRTT */
- if (seq_gt(*ea,rp->rp_sndhsa) || (rq->rq_retries[j]==0))
- {
- rp->rp_sndhsa = *ea;
- rdp_newrtt(&(rp->rp_srtt),rq->rq_sndtimer[j]);
- rp->rp_lastrtt = rq->rq_sndtimer[j];
- }
- #endif OLDRTT
-
- (void) m_freem(rq->rq_sndq[j]);
- rq->rq_sndq[j] = 0;
- }
- }
- }
- }
-
- rp->rp_inflt -= numacks;
-
- if ((rp->rp_qwait) && ((rp->rp_qwait -= numacks) <= 0))
- {
- rp->rp_qwait = 0;
-
- /* open window a bit, and set counter to open it more */
- if (++(rp->rp_maxinflt) < rp->rp_sndmax)
- rp->rp_qwait = rp->rp_maxinflt;
- }
-
- /*
- * if we have freed space, and higher level is blocked, consider
- * unblocking...
- */
-
- if ((rp->rp_inflt < rp->rp_maxinflt) && (so->so_snd.sb_cc != 0))
- {
- i = rp->rp_sndnxt - rp->rp_snduna;
-
- /* do we and remote have space? */
- if ((i < R_MAXSND) && (i < (rp->rp_sndmax << 1)))
- {
- so->so_snd.sb_cc = 0;
- sowwakeup(so);
- }
- else
- rdp_info.rst_hitedge++;
-
- }
-
- if ((ntohs(ri->ri_dlen)!=0) || (ri->ri_flags & RH_NULL))
- return(1);
-
- discard:
- /* ignore any data */
- return(0);
- }
-
- /**************************************************************************/
- /* DRAIN -- similar to OPEN, but no new data, and be lazy about EACKS */
- /**************************************************************************/
-
- rdp_idrain(inp,rp,ri)
- struct inpcb *inp;
- register struct rdpcb *rp;
- register struct rdpip *ri;
- {
- register u_long seq = ntohl(ri->ri_sn);
- register struct rdpque *rq = rp->rp_rq;
- register short i;
- register short j;
- struct mbuf *m;
- struct socket *so = inp->inp_socket;
- u_long ack;
-
- /* packet in sequence? */
- if (seq_le(seq,rp->rp_rcvcur) || seq_le(rp->rp_rcvuer,seq))
- {
- /* no ... */
- (void) rdp_ack(inp,rp->rp_sndnxt,rp->rp_rcvcur);
- rdp_info.rst_range++;
- goto discard;
- }
-
- /*
- * unlike OPEN, clearly bad close -- we haven't finished sending
- */
-
- if (ri->ri_flags & RH_RST)
- {
- so->so_error = ECONNRESET;
- soisdisconnected(so);
- rp->rp_state = R_CLOSE_WAIT;
- rp->rp_timer = RT_CLOTIME + (R_MAXTRIES * rp->rp_estrtt);
- /* again, don't send RST back */
- rq->rq_retries[0] = R_MAXTRIES;
- (void) rdp_clrq(rp);
- goto discard;
- }
-
- if (ri->ri_flags & RH_SYN)
- {
- (void) rdp_rst(inp,0,(u_long)(ntohl(ri->ri_an)+1),(u_long)0,1);
-
- /* now close down */
- inp->inp_socket->so_error = ECONNRESET;
- (void) rdp_fatal(inp);
- goto discard;
- }
-
- /* if new data then error */
- if ((ntohs(ri->ri_dlen) != 0) || (ri->ri_flags & RH_NULL))
- {
- (void) rdp_rst(inp,0,(u_long)(ntohl(ri->ri_an)+1),(u_long)0,1);
- inp->inp_socket->so_error = ECONNRESET;
- (void) rdp_fatal(inp);
- goto discard;
- }
-
- /* an ack -- maybe we are done? */
- if (ri->ri_flags & RH_ACK)
- {
- ack = ntohl(ri->ri_an);
-
- if (seq_gt(rp->rp_snduna,ack) || seq_ge(ack,rp->rp_sndnxt))
- goto discard;
-
- /* free packets acked */
- i = (ack - rp->rp_snduna)+1;
- j = rq->rq_sndbase;
-
- for(; i>0; i--)
- {
- if ((m = rq->rq_sndq[j]) != 0)
- (void) m_freem(m);
-
- if (++j == R_MAXSND)
- j = 0;
- }
-
- rq->rq_sndbase = j;
- rp->rp_snduna = ack + 1;
-
- /* are we done? -- then finish the user's close */
- if (rp->rp_snduna == rp->rp_sndnxt)
- {
- (void) rdp_rst(inp,0,rp->rp_sndnxt,(u_long)0,1);
- soisdisconnected(so);
- rp->rp_state = R_CLOSE_WAIT;
- rp->rp_timer = RT_CLOTIME + (R_MAXTRIES * rp->rp_estrtt);
- rq->rq_sndtimer[0] = 0;
- rq->rq_retries[0] = 0;
- }
- }
-
- discard:
- return(0);
- }
-
- /**************************************************************************/
- /* packet printer for debugging inbound packets */
- /**************************************************************************/
-
- #ifdef DEBUG
- rdp_pktprt(ri)
- struct rdpip *ri;
- {
- printf("s=0x%x(%d),d=0x%x(%d): ",
- ri->ri_src.s_addr, ri->ri_sport, ri->ri_dst.s_addr, ri->ri_dport);
- printf("fl=0x%x, ",(int)ri->ri_flags);
- printf("sn=0x%x,an=0x%x,",ntohl(ri->ri_sn), ntohl(ri->ri_an));
- printf("sum=0x%x,",ri->ri_sum);
- printf("hl=%d,dl=%d\n",ri->ri_hlen << 1, (int)ntohs(ri->ri_dlen));
- }
- #endif
-